package top.flvio.middleware;


import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.flvio.middleware.annotation.DBRouter;
import top.flvio.middleware.strategy.IDBRouterStrategy;

import java.lang.reflect.Field;


/**
 * @description: 数据路由切面
 * @author: flvio
 * @date: 2025/2/3
 */
@Aspect
public class DBRouterJoinPoint
{
    private Logger logger = LoggerFactory.getLogger(DBRouterJoinPoint.class);

    private DBRouterConfig dbRouterConfig;

    private IDBRouterStrategy dbRouterStrategy;

    public DBRouterJoinPoint(DBRouterConfig dbRouterConfig, IDBRouterStrategy dbRouterStrategy)
    {
        this.dbRouterConfig = dbRouterConfig;
        this.dbRouterStrategy = dbRouterStrategy;
    }

    @Pointcut("@annotation(top.flvio.middleware.annotation.DBRouter)")
    public void aopPoint(){}

    @Around("aopPoint() && @annotation(dbRouter)")
    public Object doRouter(ProceedingJoinPoint jp, DBRouter dbRouter) throws Throwable{
        String dbKey = dbRouter.key();
        if(StringUtils.isBlank(dbKey) && StringUtils.isBlank(dbRouterConfig.getRouterKey())){
            throw new RuntimeException("annotation DBRouter key is null!");
        }
        dbKey = StringUtils.isNotBlank(dbKey) ? dbKey : dbRouterConfig.getRouterKey();
        //路由属性
        String dbKeyAttr = getAttrValue(dbKey,jp.getArgs());
        //路由策略
        dbRouterStrategy.doRouter(dbKeyAttr);
        //返回结果
        try{
            return jp.proceed();
        } finally
        {
            dbRouterStrategy.clear();
        }
    }

    private String getAttrValue(String attr, Object[] args)
    {
        if (args == null || args.length == 0) {
            throw new IllegalArgumentException("参数数组不能为空");
        }

        if(1 == args.length){
            Object arg = args[0];
            if(arg instanceof String){
                return arg.toString();
            }
        }
        String fieldValue = null;
        for(Object arg : args){
            try{
                if(StringUtils.isNotBlank(fieldValue)){
                    break;
                }
                // filedValue = BeanUtils.getProperty(arg,attr);
                // fix: 使用lombok时，uid这种字段的get方法与idea生成的get方法不同，会导致获取不到属性值，改成反射获取解决
                fieldValue = String.valueOf(this.getValueByName(arg,attr));
            } catch (Exception e){
                logger.error("获取路由属性失败 attr:{}",attr,e);
            }
        }
        return fieldValue;
    }


    private Object getValueByName(Object item, String name)
    {
        try
        {
            Field field = getFieldByName(item,name);
            field.setAccessible(true);
            Object o = field.get(item);
            field.setAccessible(false);
            return o;
        }
        catch (IllegalAccessException e)
        {
            return null;
        }
    }

    private Field getFieldByName(Object item, String name)
    {
        Class<?> clazz = item.getClass();
        while(clazz != null){
            try
            {
                return clazz.getDeclaredField(name);
            }
            catch (NoSuchFieldException e)
            {
                clazz = clazz.getSuperclass();
            }
        }
        return null;
    }
}
